﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Data;
using Jb.Common.Extensions;
using Jb.Domain;
using Jb.Web.ViewModels;
using Jb.Web.Utility;
using AutoMapper;
using Jb.Web.ViewModels.UtilityModels;
using System.Text;
using Jb.Search;
using Jb.Search.Searcher;

namespace Jb.Web.Controllers
{
    public class JobController : BaseController
    {
		private JbEntities _Context = new JbEntities();
        
		#region Constructors
		public JobController()
		{
		}

		public JobController(UserViewModel currentUser)
			: base(currentUser)
        {
        }
		#endregion Constructors

		#region Action Methods
        public ActionResult Index()
        {
            return View();
        }
		/// <summary>
        /// Gets a Job from Database to edit
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
		public ActionResult Details(int id = 0)
        {
            Job entity = _Context.Jobs
                .Include("Company").Include("JobLevel")
                .Include("JobEducations").Include("JobSkills")
                .Include("City")
                .FirstOrDefault(P => P.ID == id);
            JobViewModel viewModel = Mapper.Map<Job, JobViewModel>(entity);
            if (viewModel != null)
            {
                ReadEducationAndSkill(entity, viewModel);
                JobUtil.SetJobLocation(entity, viewModel);
                SetJobTemplate(viewModel);
                WebUtil.MapZGL(viewModel, entity.Category.PropertyDefinition);
            }
            return View(viewModel);
        }

        /// <summary>
        /// Handles the GET request for Job Apply
        /// </summary>
        /// <param name="id"></param>
        /// <param name="isPost"></param>
        /// <param name="isSaved"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public ActionResult Apply(int id = 0, String isPost = null, String isSaved = null, String status = null )
        {
            JobApplicationViewModel viewModel = new JobApplicationViewModel();
            viewModel.JobID = id;
            BuildJobApplicationProperties(viewModel);
            if (UserInfo.IsJobSeeker)
            {
                int applicationCount = _Context.JobApplications.Count(P => P.JobID == viewModel.JobID && P.Resume.JobSeekerID == LoggedInUser.JobSeekerID);
                ViewData[AppConstants.ViewDataKeys.GENERIC_KEY] = applicationCount > 0 ? true : false;
            }
            return View(viewModel);
        }        

        /// <summary>
        /// Saves Job Application. Handles POST request
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Apply(JobApplicationViewModel viewModel)
        {
            if (!ModelState.IsValid)
            {
                BuildJobApplicationProperties(viewModel);
                return View(viewModel);
            }
            ///Check for profile completeness during job apply.
            if (UserInfo.IsJobSeeker && !LoggedInUser.JobSeekerInfo.HasProfileCompleted)
            {
                BuildJobApplicationProperties(viewModel);
                return View(viewModel);
            }
            ///Only new applications are accepted
            if (viewModel.ID == 0)
            {
                JobApplication entity = new JobApplication();
                entity = Mapper.Map<JobApplicationViewModel, JobApplication>(viewModel, entity);
                entity.AppliedOn = DateTime.Now;
                
                _Context.AddToJobApplications(entity);
                _Context.SaveChanges();
                SendNotificationToJobOwners(entity);
                return RedirectToAction("Apply", new { IsPost = "true", IsSaved = "true", Status = "1" });
            }
            return RedirectToAction("Apply", new { IsPost = "true", IsSaved = "false", Status = "10" });
        }

        /// <summary>
        /// Lists Jobs by category
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult Category(String id, String pageNo)
        {
            CategoryViewModel category = ApplicationCache.Categories.FirstOrDefault(C => String.Compare(C.UrlName, id, true) == 0);
            if(category != null)
            {
                String categoryIDs = JobUtil.GetRelatedCategories(category);
                UtilityDAO dao = new UtilityDAO();

                DbParameter[] parameters =
                    new[] { 
                        new DbParameter("@CategoryIDs", categoryIDs)
                        //, new DbParameter("@UserID", SessionCache.CurrentUser == null ? 0 : SessionCache.CurrentUser.ID) 
                };

                PagerConfig pagerConfig = new PagerConfig(pageNo.ToInt() > 0 ? pageNo.ToInt() : 1, ConfigReader.PageSize, 0);
                int totalRecord = 0;
                System.Data.DataSet ds = dao.GetPagedData(DbObject.SP.GET_PAGED_JOBS_BY_CATEGORY, parameters, pagerConfig.PageNo, pagerConfig.PageSize, out totalRecord, true);
                pagerConfig.TotalRecord = totalRecord;
                ViewBag.ShowEditLink = false;
                ListConfig listConfig = new ListConfig(ds.Tables[0], pagerConfig);
                ViewData[AppConstants.ViewDataKeys.SUB_MODEL] = listConfig;
            }
            return View(category);
        }

		#endregion Action Methods

        #region Simple Job Search Action Methods

        /// <summary>
        /// The main job search engine controller method
        /// </summary>
        /// <param name="key"></param>
        /// <param name="pageNo"></param>
        /// <returns></returns>
        public ActionResult Search(String key, String pageNo)
        {
            if (key.IsNullOrEmpty())
                return View(new ListConfig(null, new PagerConfig()));
            key = key.UrlDecode();
            PagerConfig pagerConfig = new PagerConfig(pageNo.ToInt() > 0 ? pageNo.ToInt() : 1, ConfigReader.PageSize, 0);

            int totalRecord = 0;
            ///Search in Lucene Index
            ISearcher searcher = SearcherFactory.GetSearcher(typeof(Job));
            //String jobIDs = searcher.Search(key, pagerConfig.PageSize, pagerConfig.PageNo, out totalRecord); //"4,5,6,7,8,9,10"; 
            String jobIDs = searcher.Search(key);
            
            //pagerConfig.TotalRecord = totalRecord;

            ///Get the Resulting Product Information from Database
            UtilityDAO dao = new UtilityDAO();
            DbParameter[] parameters = new[] { 
                new DbParameter("@JobIDs", jobIDs)
                //, new DbParameter("@UserID", SessionCache.CurrentUser == null ? 0 : SessionCache.CurrentUser.ID)
            };
            DataSet ds = dao.GetPagedData(DbObject.SP.GET_PAGED_JOBS_BY_ID, parameters, pagerConfig.PageNo, pagerConfig.PageSize, out totalRecord, true);
            ListConfig listConfig = new ListConfig(ds.Tables[0], pagerConfig);
            pagerConfig.TotalRecord = totalRecord;
            ViewData[AppConstants.ViewDataKeys.SEARCH_KEY] = key;
            return View(listConfig);
        }

        /// <summary>
        /// Post method to process job search keyword only.
        /// </summary>
        /// <param name="keyword"></param>
        /// <returns></returns>
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Search(String keyword)
        {
            keyword = keyword.UrlEncode();
            return RedirectToAction("search", new { key = keyword, pageNo = 1 });
        }

        #endregion Simple Job Search

        #region Advanced Job Search Action Methods

        public ActionResult AdvancedSearch()
        {
            SavedSearchViewModel model = new SavedSearchViewModel();
            return View(model);
        }

        [HttpPost]
        public ActionResult AdvancedSearch(SavedSearchViewModel viewModel)
        {
            int pageNo = viewModel.PageNo.ToInt();
            PagerConfig pager = new PagerConfig(pageNo > 0 ? pageNo : 1, ConfigReader.PageSize, 0);
            String categoriesToSearch = String.Empty;
            if (viewModel.CategoryID.HasValue)            
                categoriesToSearch = JobUtil.GetRelatedCategories(viewModel.CategoryID.GetValueOrDefault());

            SavedSearcher searcher = new SavedSearcher(_Context, categoriesToSearch);
            SavedSearch savedSearch = Mapper.Map<SavedSearchViewModel, SavedSearch>(viewModel);
            
            int totalRecord = 0;
            DataSet ds = searcher.ExecuteSearch(savedSearch, pager.PageNo, pager.PageSize, out totalRecord);
            pager.TotalRecord = totalRecord;
            if(ds != null)
                viewModel.ResultSet = new ListConfig(ds.Tables[0], pager);
            if(totalRecord == 0)
                return Content(String.Empty);

            return PartialView("_AdvancedSearchResult", viewModel.ResultSet);
        }
        #endregion Advanced Job Search Action Methods

        #region Helper Methods

        private void ReadEducationAndSkill(Job entity, JobViewModel viewModel)
        {
            //var selectedEducations = entity.JobEducations.ToList();
            //var selectedSkills = entity.JobSkills.ToList();
            //List<JobEducation> sortedEducation = selectedEducations.OrderBy(O => O.EducationID).ToList();

            foreach (var jobEducation in entity.JobEducations)//.OrderBy(P => P.EducationID).OrderBy(P => P.Education.Name))
            {
                if (jobEducation.Education == null)
                    viewModel.SelectedEducations.Add(new GenericViewModel() { ID = null, Name = jobEducation.OtherEducation });
                else
                    viewModel.SelectedEducations.Add(new GenericViewModel() { ID = jobEducation.EducationID, Name = jobEducation.Education.Name });
            }
            foreach (var jobSkill in entity.JobSkills)//.OrderBy(P => P.SkillID).OrderBy(P => P.Skill.Name))
            {
                if (jobSkill.Skill == null)
                    viewModel.SelectedSkills.Add(new GenericViewModel() { ID = null, Name = jobSkill.OtherSkill });
                else
                    viewModel.SelectedSkills.Add(new GenericViewModel() { ID = jobSkill.SkillID, Name = jobSkill.Skill.Name });
            }
        }

        private void SetJobTemplate(JobViewModel viewModel)
        {            
            JobTemplate template = _Context.JobTemplates.FirstOrDefault(P => P.CompanyID == viewModel.CompanyID && P.IsActive);
            JobTemplateViewModel jobTemplateViewModel = new JobTemplateViewModel();
            if (template == null)
            {
                template = new JobTemplate();
                template.RelativePath = ConfigReader.DefaultJobTemplatePath;
                jobTemplateViewModel.IsDefault = true;
            }
            viewModel.JobTemplate = Mapper.Map<JobTemplate, JobTemplateViewModel>(template, jobTemplateViewModel);
        }

        /// <summary>
        /// Sets the job object, Default resume and Coverletter for the logged in job seeker
        /// </summary>
        /// <param name="viewModel"></param>
        private void BuildJobApplicationProperties(JobApplicationViewModel viewModel)
        {
            ///Select the Active Job
            Job jobEntity = _Context.Jobs.Include("Company").FirstOrDefault(P => P.ID == viewModel.JobID && P.IsActive && !P.IsDeleted && P.Company.IsActive);
            viewModel.Job = Mapper.Map<Job, JobViewModel>(jobEntity);
            //ViewData[AppConstants.ViewDataKeys.JOB_TO_APPLY] = jobViewModel;
            if (UserInfo.IsJobSeeker)
            {
                ///Map Default Cover Letter
                CoverLetter defaultCoverLetter = _Context.CoverLetters.FirstOrDefault(P => P.JobSeekerID == LoggedInUser.JobSeekerID && P.IsDefault);
                if (defaultCoverLetter == null)
                {
                    ///Jora Tali, to bypass model validation check after post back
                    CoverLetterViewModel defaultViewModel = new CoverLetterViewModel();
                    defaultViewModel.IsDefault = "true";
                    defaultViewModel.Title = "N/A";
                    defaultViewModel.Application = "N/A";
                    viewModel.DefaultCoverLetter = defaultViewModel;
                }
                else
                {
                    CoverLetterViewModel coverLetterViewModel = Mapper.Map<CoverLetter, CoverLetterViewModel>(defaultCoverLetter);
                    viewModel.DefaultCoverLetter = coverLetterViewModel;
                    viewModel.CoverLetter = coverLetterViewModel.Application;
                }
                Resume defalutResume = _Context.Resumes.FirstOrDefault(P => P.JobSeekerID == LoggedInUser.JobSeekerID && P.IsDefault);
                if (defalutResume != null)
                    viewModel.ResumeID = defalutResume.ID;
            }
        }

        /// <summary>
        /// Sends a Email Notification to the Job Owner, after a job application is received.
        /// </summary>
        /// <param name="entity"></param>
        private int SendNotificationToJobOwners(JobApplication application)
        {
            StringBuilder template = new StringBuilder(WebUtil.ReadEmailTemplate(AppConstants.EmailTemplate.COMMON));
            StringBuilder message = new StringBuilder(10);
            message.Append("Hi,<br />");
            message.AppendFormat("A new candidate has applied to the following job:<br/><br/>");
            message.AppendFormat("<b>Job Title:</b><br/> {0}<br/><br/>", WebUtil.FormatData(application.Job.Title));
            //message.AppendFormat("<b>Job Description:</b><br/> {0}<br/><br/>", WebUtil.FormatData(application.Job.Description));
            message.AppendFormat("For more details visit this <a href='{0}{1}'>job details</a> page. <br/><br/>", WebUtil.GetDomainAddress(), Url.JobDetailsUrl(application.JobID, application.Job.Url));
            ///Set job seeker photo
            message.AppendFormat("<div><img src='{0}{1}' alt='{2}' title='{2}'/></div>", 
                WebUtil.GetDomainAddress(),
                ImageManager.GetJobSeekerPhotoUrl(application.Resume.JobSeeker.PhotoFile, application.Resume.JobSeekerID), 
                WebUtil.FormatData(application.Resume.JobSeeker.Name));
            message.AppendFormat("<b>Job Seeker Name:</b><br/> {0}<br/><br/>", WebUtil.FormatData(application.Resume.JobSeeker.Name));
            message.AppendFormat("<b>Job Seeker Cover Letter:</b><br/> {0}<br/><br/>", WebUtil.FormatData(application.CoverLetter));
            message.AppendFormat("<b>Resume Snap Shot:</b><br/> {0}<br/><br/>", WebUtil.FormatData(application.Resume.SnapShot));

            template.Replace(AppConstants.ETConstants.MESSAGE, message.ToString());
            template.Replace(AppConstants.ETConstants.DOMAIN, WebUtil.GetDomainAddress());
            ///Filter out the emails of company and company contacts those should receive this email
            Company company = _Context.Companies.Include("Address").FirstOrDefault(P => P.ID == application.Job.CompanyID);
            StringBuilder toEmail = new StringBuilder(10);
            if (company.Address.Email.IsEmail())
                toEmail.Append(company.Address.Email);

            ///Filter Contact Emails
            foreach(Contact contact in company.Contacts)
            {
                if (contact.Address.Email.IsEmail())
                {
                    if (toEmail.Length == 0)
                        toEmail.Append(contact.Address.Email);
                    else
                        toEmail.AppendFormat(",{0}", contact.Address.Email);
                }
            }
            String subject = String.Format("New Job Application Received for the job: {0}", WebUtil.FormatData(application.Job.Title));
            if (WebUtil.SendMail(application.Resume.JobSeeker.Address.Email, toEmail.ToString(), ConfigReader.AdminEmail, String.Empty, subject, template.ToString()))
                return 1;

            return -1;
        }

        #endregion			
    }
}


